package com.fire8.dolphin.service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.provider.PrivacyProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.GroupChatInvitation;
import org.jivesoftware.smackx.PrivateDataManager;
import org.jivesoftware.smackx.ReportedData;
import org.jivesoftware.smackx.ReportedData.Column;
import org.jivesoftware.smackx.ReportedData.Row;
import org.jivesoftware.smackx.packet.ChatStateExtension;
import org.jivesoftware.smackx.packet.LastActivity;
import org.jivesoftware.smackx.packet.OfflineMessageInfo;
import org.jivesoftware.smackx.packet.OfflineMessageRequest;
import org.jivesoftware.smackx.packet.SharedGroupsInfo;
import org.jivesoftware.smackx.packet.VCard;
import org.jivesoftware.smackx.provider.AdHocCommandDataProvider;
import org.jivesoftware.smackx.provider.BytestreamsProvider;
import org.jivesoftware.smackx.provider.DataFormProvider;
import org.jivesoftware.smackx.provider.DelayInformationProvider;
import org.jivesoftware.smackx.provider.DiscoverInfoProvider;
import org.jivesoftware.smackx.provider.DiscoverItemsProvider;
import org.jivesoftware.smackx.provider.MUCAdminProvider;
import org.jivesoftware.smackx.provider.MUCOwnerProvider;
import org.jivesoftware.smackx.provider.MUCUserProvider;
import org.jivesoftware.smackx.provider.MessageEventProvider;
import org.jivesoftware.smackx.provider.MultipleAddressesProvider;
import org.jivesoftware.smackx.provider.RosterExchangeProvider;
import org.jivesoftware.smackx.provider.StreamInitiationProvider;
import org.jivesoftware.smackx.provider.VCardProvider;
import org.jivesoftware.smackx.provider.XHTMLExtensionProvider;
import org.jivesoftware.smackx.search.UserSearch;
import org.jivesoftware.smackx.search.UserSearchManager;

import android.os.Handler;
import android.util.Log;

import com.fire8.dolphin.common.UserStatus;
import com.fire8.dolphin.model.UserInfo;
import com.fire8.dolphin.service.xmpp.EventTypes;
import com.fire8.dolphin.service.xmpp.MessageProcessHandler;
import com.fire8.dolphin.ui.DolphinApplication;
import com.fire8.dolphin.utils.LogUtil;

/**
 * Jaber 客户端的service类，负责跟Jaber服务器通讯，如连接服务器； 注册，登录，收发信息
 * 
 * 
 * @author ben
 * 
 */
public class JaberClientService
{
    
    private static final JaberClientService SERVICE = new JaberClientService();
    
    private static final String DEFAULT_GROUP_NAME = "Friends";
    
    private ConnectionConfiguration connectionConfig;
    
    private XMPPConnection conn;
    
    private Handler mHandler;
    
    private List<MessageProcessHandler> listeners = new Vector<MessageProcessHandler>();
    
    private Map<String, Chat> chats = new Hashtable<String, Chat>();
    
    private JaberClientService()
    {
    }
    
    public static JaberClientService getInstance()
    {
        return SERVICE;
    }
    public void setHandler(Handler handler)
    {
        mHandler = handler;
    }
    public void addMessageListener(MessageProcessHandler handler)
    {
        listeners.add(handler);
    }
    public boolean isConnected()
    {
        if (conn != null && conn.isConnected())
        {
            return true;
        }else
        {
            return false;
        }
    }
    public void connect() throws XMPPException
    {
        if (conn != null && conn.isConnected())
        {
            return;
        }
        LogUtil.d("连接openfire 服务器...");
        //XMPPConnection.DEBUG_ENABLED = true;
        connectionConfig = new ConnectionConfiguration(DolphinApplication.IP, 3157);
        conn = new XMPPConnection(connectionConfig);
        //conn.DEBUG_ENABLED = true;
        conn.connect();
        LogUtil.d("连接状态：：：" + (conn.isConnected() ? "成功" : "失败"));
    }
    
    /**
     * 注册用户
     * @param username 用户名
     * @param password 密码
     * @throws XMPPException
     */
    public void register(String username, String password) throws XMPPException
    {
        Map<String, String> map = new HashMap<String, String>();
        map.put("aaa", "xxx");
        conn.getAccountManager().createAccount(username, password, map);
    }
    
    /**
     * 登录 
     * @param username
     * @param password
     * @throws XMPPException
     */
    public void login(String username, String password) throws XMPPException
    {
        conn.login(username, password);
        notifyOnline();
        this.conn.getRoster()
                .setSubscriptionMode(Roster.SubscriptionMode.manual);
        
        //增加数据包监听器
        conn.addPacketListener(new PacketListener()
        {
            
            @Override
            public void processPacket(Packet packet)
            {
                LogUtil.d("收到数据包...");
                android.os.Message msg = new android.os.Message();
                if (packet instanceof Presence)
                {//(1)状态消息
                
                    /*
                     * Presence.Type.subscribe 加好友
                     * Presence.Type.unsubscribe 加好友:被拒绝
                     * Presence.Type.subscribed 允许某人的好友添加
                     * Presence.Type.unsubscribed 拒绝某人的好友添加
                     */
                    
                    Presence presence = (Presence)packet;
                    LogUtil.d("Presence消息类型：" + presence.getType());
                    if (presence.getType() == Presence.Type.unsubscribe)
                    {
                        
                        msg.what = EventTypes.ADD_FRIEND_REFUSED;
                        msg.obj = presence;
                        mHandler.sendMessage(msg);
//                        for (MessageProcessHandler handler : listeners)
//                        {
//                            JaberMessenger.sendAddFriendRefusedMsg(handler,
//                                    presence);
//                        }
                    }
                    else if (presence.getType() == Presence.Type.subscribe)
                    {
                        LogUtil.d("subscribe..........");
                        msg.what = EventTypes.BE_ADD_FRIEND;
                        msg.obj = presence;
                        mHandler.sendMessage(msg);
//                        for (MessageProcessHandler handler : listeners)
//                        {
//                            JaberMessenger.sendBeAddFriendMsg(handler, presence);
//                        }
                    }else if (presence.getType() == Presence.Type.subscribed)
                    {
                        LogUtil.d("["+presence.getFrom()+"]同意你的加好友请求");
                        //同意加为好友
                        msg.what = EventTypes.ADD_FRIEND_ED;
                        msg.obj = presence;
                        mHandler.sendMessage(msg);
                    }else if (presence.getType() == Presence.Type.error)
                    {
                        LogUtil.d("数据包：" + presence.getType() + ":来自["
                                + presence.getFrom() + "]的错误信息：" + presence.getError());
                        
                    }else
                    {
                        LogUtil.d("来自["+presence.getFrom()+"]未知的消息类型："+presence.getType());
                    }
                    
                }
                else if (packet instanceof Message)
                {//(2)聊天消息
                    Message message = (Message)packet;
                    if (message.getType() == Message.Type.chat)
                    {//现在只处理个人聊天消息
                        LogUtil.d("Message消息啊：" + message.getType() + ":来自["
                                + message.getFrom() + "]" + message.getBody());
                        msg.what = EventTypes.CHAT_MSG;
                        msg.obj = message;
                        mHandler.sendMessage(msg);
                    }
                    
                }
                else{
                    LogUtil.e("未知的数据包类型:"+packet.toXML());
                }
            }
        },
                new PacketFilter()
                {
                    
                    @Override
                    public boolean accept(Packet packet)
                    {
                        if (packet instanceof Presence)
                        {
                            return true;
                        }
                        return true;
                    }
                });
        
        //增加好友状态监听器
        this.conn.getRoster().addRosterListener(new RosterListener()
        {
            
            @Override
            public void presenceChanged(Presence presence)
            {
                
            }
            
            @Override
            public void entriesUpdated(Collection<String> addresses)
            {
                
            }
            
            @Override
            public void entriesDeleted(Collection<String> addresses)
            {
                
            }
            
            @Override
            public void entriesAdded(Collection<String> addresses)
            {
                
            }
        });
    }
    
    /**
     * 发消息
     * @param to
     * @param msgContent
     * @throws XMPPException 
     */
    public void sendMessage(String to, String msgContent) throws XMPPException
    {
        getChat(to).sendMessage(msgContent);
    }
    
    /** 回复添加好友的请求
     * @param jid
     * @param agree 是否同意
     * 
     */
    public void responseToAddFriend(String jid, boolean agree)
    {
        LogUtil.d((agree ? "同意了[" : "拒绝了[") + jid + "]的好友添加");
        
        Type type = agree ? Presence.Type.subscribed
                : Presence.Type.unsubscribed;
        Presence presence = new Presence(type);
        presence.setFrom(getCurrentUser());
        presence.setTo(jid);
        conn.sendPacket(presence);
    }
    
    public void requestAddFriend(String username) throws XMPPException
    {
        LogUtil.d("发起加好友的请求:" + userIdToJaberID(username));
        //this.conn.getRoster().setSubscriptionMode(Roster.SubscriptionMode.)
        //昵称
        String nickname = username;
        this.conn.getRoster().createEntry(userIdToJaberID(username),
                nickname,
                new String[] {DEFAULT_GROUP_NAME});
    }
    
    /**
     * 返回所有用户信息
     * <功能详细描述>
     * @return [参数说明]
     *
     * @author lixg
     * @see [类、类#方法、类#成员]
     */
    public List<UserInfo> getFriends()
    {
        LogUtil.d("获取好友列表---------------------------------");
        List<UserInfo> friends = new ArrayList<UserInfo>();
        Collection<RosterGroup> groups = this.conn.getRoster().getGroups();
        LogUtil.d("组数量:"+groups.size());
        for (RosterGroup group : groups)
        {
            Collection<RosterEntry> entries = group.getEntries();
            LogUtil.d("entries:"+entries.size());
            for (RosterEntry entry : entries)
            {
                if (entry.getType() != RosterPacket.ItemType.remove)
                {
                    
                    UserInfo u = new UserInfo();
                    u.setAccount(entry.getUser());
                    u.setUserName(entry.getName());
                    u.setStatus(this.conn.getRoster()
                            .getPresence(entry.getUser())
                            .getStatus());
                    if (u.getStatus() == null)
                    {
                        u.setStatus(UserStatus.OFF_LINE);
                    }
                    friends.add(u);
                    LogUtil.d("---------------------------------------------------------------");
                    LogUtil.d("type:" + entry.getType());
                    LogUtil.d("用户名：" + u.getUserName());
                    LogUtil.d("用户状态：" + u.getStatus());
                }
            }
        }
        
        return friends;
    }
    
    /**
     * 根据用户id拼接完整的服务器认识的id 
     * 如： test1@server.com
     * @param userid
     * @return
     */
    private String userIdToJaberID(String username)
    {
        return username + "@" + this.conn.getServiceName();
    }
    
    public void disConn()
    {
        LogUtil.d("与openfire服务器断开连接");
        Presence unPresence = new Presence(Presence.Type.unavailable);
        unPresence.setStatus(UserStatus.OFF_LINE);
        this.conn.disconnect(unPresence);
    }
    
    private String getCurrentUser()
    {
        return conn.getUser();
    }
    
    /**
     * 发送消息通知本人在线
     */
    private void notifyOnline()
    {
        Presence presence = new Presence(Presence.Type.available);
        presence.setStatus(UserStatus.ON_LINE);
        conn.sendPacket(presence);
    }
    
    private Chat getChat(String userid)
    {
        String jid = this.userIdToJaberID(userid);
        Chat chat = this.chats.get(jid);
        if (chat == null)
        {
            chat = this.conn.getChatManager().createChat(jid,
                    new MessageListener()
                    {
                        
                        @Override
                        public void processMessage(Chat chat, Message message)
                        {
                            LogUtil.d("MessageListener:" + message.getFrom());
                        }
                    });
            chats.put(jid, chat);
        }
        
        return chat;
    }
    
    public String getUserRealName(String search) {   
        LogUtil.d("getUserRealName");
        configure(ProviderManager.getInstance());
        String name = null;   
        try {   
              
  
                ReportedData data;   
                UserSearchManager usersearchManager = new UserSearchManager(   
                        this.conn);   
                LogUtil.d("usersearchManager:"+conn.getServiceName());
                Form searchForm = usersearchManager.getSearchForm("search."+conn.getServiceName());   
  
                Form answer = searchForm.createAnswerForm();//设置搜索条件   
                answer.setAnswer("Name", true);   
                answer.setAnswer("Email", true);   
                answer.setAnswer("Username", true);   
                answer.setAnswer("search", "t");   
  
                data = usersearchManager.getSearchResults(answer, "search."+conn.getServiceName());   
                
                ArrayList<String> columnnames = new ArrayList<String>();   
                Iterator<Column> columns = data.getColumns();   
                
                while (columns.hasNext()) {   
                    ReportedData.Column column = (ReportedData.Column) columns   
                            .next();   
                    String label = column.getLabel();   
                    columnnames.add(label);   
                    LogUtil.d("---------"+label+"---------");
                }   
  
                Iterator<Row> rows = data.getRows();   
                if (rows.equals("") || rows == null) {   
                    LogUtil.d("title.user.not.exists");
                      
                } 
                
                while (rows.hasNext()) {   
                    
                    ReportedData.Row row = (ReportedData.Row) rows.next();   
                    if(row.getValues(columnnames.get(1)).hasNext()){   
                        LogUtil.d("col1:"+row.getValues(columnnames.get(1)).next());
                        if (row.getValues(columnnames.get(2)).hasNext()) {   
                            name = (String) row.getValues(columnnames.get(2)).next();//得到具体用户名   
                            LogUtil.d("col2:"+name);
                        }   
                    }   
  
                }   
             
        } catch (Exception e) {   
            LogUtil.e("",e);
        }   
        return name;   
    } 
    
    public void configure(ProviderManager pm) {

    //  Private Data Storage
    pm.addIQProvider("query","jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());

    //  Time
    try {
        pm.addIQProvider("query","jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
    } catch (ClassNotFoundException e) {
        Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
    }

    //  Roster Exchange
    pm.addExtensionProvider("x","jabber:x:roster", new RosterExchangeProvider());

    //  Message Events
    pm.addExtensionProvider("x","jabber:x:event", new MessageEventProvider());

    //  Chat State
    pm.addExtensionProvider("active","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); 
    pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());

    //  XHTML
    pm.addExtensionProvider("html","http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());

    //  Group Chat Invitations
    pm.addExtensionProvider("x","jabber:x:conference", new GroupChatInvitation.Provider());

    //  Service Discovery # Items    
    pm.addIQProvider("query","http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());

    //  Service Discovery # Info
    pm.addIQProvider("query","http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());

    //  Data Forms
    pm.addExtensionProvider("x","jabber:x:data", new DataFormProvider());

    //  MUC User
    pm.addExtensionProvider("x","http://jabber.org/protocol/muc#user", new MUCUserProvider());

    //  MUC Admin    
    pm.addIQProvider("query","http://jabber.org/protocol/muc#admin", new MUCAdminProvider());

    //  MUC Owner    
    pm.addIQProvider("query","http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());

    //  Delayed Delivery
    pm.addExtensionProvider("x","jabber:x:delay", new DelayInformationProvider());

    //  Version
    try {
        pm.addIQProvider("query","jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
    } catch (ClassNotFoundException e) {
        //  Not sure what's happening here.
    }

    //  VCard
    pm.addIQProvider("vCard","vcard-temp", new VCardProvider());

    //  Offline Message Requests
    pm.addIQProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());

    //  Offline Message Indicator
    pm.addExtensionProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());

    //  Last Activity
    pm.addIQProvider("query","jabber:iq:last", new LastActivity.Provider());

    //  User Search
    pm.addIQProvider("query","jabber:iq:search", new UserSearch.Provider());

    //  SharedGroupsInfo
    pm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider());

    //  JEP-33: Extended Stanza Addressing
    pm.addExtensionProvider("addresses","http://jabber.org/protocol/address", new MultipleAddressesProvider());

    //   FileTransfer
    pm.addIQProvider("si","http://jabber.org/protocol/si", new StreamInitiationProvider());

    pm.addIQProvider("query","http://jabber.org/protocol/bytestreams", new BytestreamsProvider());

    //  Privacy
    pm.addIQProvider("query","jabber:iq:privacy", new PrivacyProvider());
    pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
    pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError());
    pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError());
    pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError());
    pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError());
    pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError());
    }
    
    public static void main(String[] args) throws XMPPException
    {
        String name = "test3";
        JaberClientService s = new JaberClientService();
        s.connect();
        //s.register(name, "123456");
        s.login(name, "123456");
        s.requestAddFriend("test1");
        try
        {
            MessageDigest md = MessageDigest.getInstance("md5");
            
        }
        catch (NoSuchAlgorithmException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
